home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / rhinosrc.lha / popcli.c < prev    next >
C/C++ Source or Header  |  1993-06-09  |  10KB  |  482 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *    facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *      with later releases (NOS0522).
  8.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *    Some code culled from previous releases of SMTP.
  11.  *
  12.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *    Permission granted for non-commercial copying and use, provided
  16.  *      this notice is retained.
  17.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *      also rebuilt locking mechanism
  19.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *    Permission granted for non-commercial copying and use, provided
  21.  *    this notice is retained.
  22.  */
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <time.h>
  26. #include <setjmp.h>
  27. #ifdef UNIX
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef    __TURBOC__
  31. #include <dir.h>
  32. #include <io.h>
  33. #endif
  34. #include "global.h"
  35. #ifdef    ANSIPROTO
  36. #include <stdarg.h>
  37. #endif
  38. #include "mbuf.h"
  39. #include "cmdparse.h"
  40. #include "proc.h"
  41. #include "socket.h"
  42. #include "timer.h"
  43. #include "netuser.h"
  44. #include "dirutil.h"
  45. #include "files.h"
  46. #include "commands.h"
  47.  
  48. extern char Badhost[];
  49.  
  50. #define BUF_LEN        257
  51.  
  52. /* POP client control block */
  53.  
  54. struct pop_ccb {
  55.     FILE *network;        /* Network stream for this connection */
  56.     char    state;        /* client state */
  57. #define       CALL        0
  58. #define       NMBR        3
  59. #define       SIZE        5
  60. #define       XFER        8
  61. #define       EXIT        10
  62.     char    buf[BUF_LEN],    /* tcp input buffer */
  63.         count;        /* input buffer length */
  64.     int    folder_len;    /* number of msgs in current folder */
  65.     long    msg_len;    /* length of current msg */
  66.     int    msg_num;    /* current message number */
  67. } *ccb;
  68.  
  69. #define NULLCCB        (struct pop_ccb *)0
  70.  
  71. static int Popquiet = 0;
  72.  
  73. static struct timer  popcli_t;
  74. static int32 mailhost;
  75. static char    mailbox_name[10],
  76.         mailbox_pathname[BUF_LEN],
  77.         username[20],
  78.         password[20],
  79.         Workfile_name[] ="mbox.pop";
  80.  
  81. static int domailbox __ARGS((int argc,char *argv[],void *p));
  82. static int domailhost __ARGS((int argc,char *argv[],void *p));
  83. static int douserdata __ARGS((int argc,char *argv[],void *p));
  84. static int doquiet __ARGS((int argc,char *argv[],void *p));
  85. static int dotimer __ARGS((int argc,char *argv[],void *p));
  86. static struct pop_ccb     *new_ccb __ARGS((void));
  87. static void delete_ccb __ARGS((void));
  88. static void pop_send __ARGS((int unused,void *cb1,void *p));
  89. static int popkick __ARGS((int argc,char *argv[],void *p));
  90.  
  91. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  92. int poptick __ARGS((void));
  93.  
  94. static struct cmds Popcmds[] = {
  95.     "mailbox",    domailbox,    0,    0,    NULLCHAR,
  96.     "mailhost",    domailhost,    0,    0,    NULLCHAR,
  97.     "kick",        popkick,    0,    0,    NULLCHAR,
  98.     "quiet",    doquiet,    0,    0,    NULLCHAR,
  99.     "timer",    dotimer,    0,    0,    NULLCHAR,
  100.     "userdata",    douserdata,    0,    0,    NULLCHAR,
  101.     NULLCHAR,
  102. };
  103.  
  104.  
  105. /* Command string specifications */
  106.  
  107. static char ackd_cmd[] = "ACKD\n",
  108. #ifdef POP_FOLDERS
  109.     fold_cmd[] = "FOLD %s\n",
  110. #endif
  111.     login_cmd[] = "HELO %s %s\n",
  112.     /* nack_cmd[]      = "NACK\n",     /* Not implemented */
  113.     quit_cmd[]      = "QUIT\n",
  114.     read_cur_cmd[]  = "READ\n",
  115.     retr_cmd[]      = "RETR\n";
  116.  
  117. /* Response string keys */
  118.  
  119. static char *greeting_rsp  = "+ POP2 ";
  120.  
  121. FILE    *fd;
  122. #define    NULLFILE    (FILE *)0
  123.  
  124. int
  125. dopop(argc,argv,p)
  126. int     argc;
  127. char     *argv[];
  128. void     *p;
  129. {
  130.     return subcmd(Popcmds,argc,argv,p);
  131. }
  132.  
  133. static int
  134. domailbox(argc,argv,p) 
  135. int argc;
  136. char *argv[];
  137. void *p;
  138. {
  139.     if(argc < 2) {
  140.         if(mailbox_name[0] == '\0')
  141.             printf("maibox name not set yet\n");
  142.         else
  143.             printf("%s\n",mailbox_name);
  144.     } else {
  145.         strncpy(mailbox_name,argv[1],10);
  146.     }
  147.  
  148.     return 0;
  149. }
  150.  
  151. static int
  152. domailhost(argc,argv,p)
  153. int argc;
  154. char *argv[];
  155. void *p;
  156. {
  157.     int32 n;
  158.  
  159.     if(argc < 2) {
  160.         printf("%s\n",inet_ntoa(mailhost));
  161.     } else
  162.         if((n = resolve(argv[1])) == 0) {
  163.             printf(Badhost,argv[1]);
  164.             return 1;
  165.         } else
  166.             mailhost = n;
  167.  
  168.     return 0;
  169. }
  170.  
  171. static int
  172. doquiet(argc,argv,p)
  173. int argc;
  174. char *argv[];
  175. void *p;
  176. {
  177.     return setbool(&Popquiet,"POP quiet",argc,argv);
  178. }
  179.  
  180. static int
  181. douserdata(argc,argv,p)
  182. int argc;
  183. char *argv[];
  184. void *p;
  185. {
  186.     if (argc < 2)
  187.         printf("%s\n",username);
  188.     else if (argc != 3) {
  189.         printf("Usage: pop userdata <username> <password>\n");
  190.         return 1;
  191.     } else {
  192.         sscanf(argv[1],"%18s",username);
  193.         sscanf(argv[2],"%18s",password);
  194.     }
  195.  
  196.     return 0;
  197. }
  198.  
  199. /* Set scan interval */
  200.  
  201. static int
  202. dotimer(argc,argv,p)
  203. int argc;
  204. char *argv[];
  205. void *p;
  206. {
  207.     if(argc < 2) {
  208.         printf("%lu/%lu\n",
  209.             read_timer(&popcli_t) /1000L,
  210.             dur_timer(&popcli_t)/ 1000L);
  211.         return 0;
  212.     }
  213.  
  214.     popcli_t.func  = (void (*)())poptick;          /* what to call on timeout */
  215.     popcli_t.arg   = NULL;                /* dummy value */
  216.     set_timer(&popcli_t, atol(argv[1])*1000L);     /* set timer duration */
  217.     start_timer(&popcli_t);                /* and fire it up */
  218.     return 0;
  219. }
  220.  
  221. static int
  222. popkick(argc,argv,p)
  223. int argc;
  224. char *argv[];
  225. void *p;
  226. {
  227.     poptick();
  228.     return 0;
  229. }
  230.  
  231. int
  232. poptick()
  233. {
  234.     if (ccb == NULLCCB) {
  235.  
  236.         /* Don't start if any of the required parameters have not been specified */
  237.  
  238.         if (mailhost == 0) {
  239.             printf("mailhost not defined yet.(pop mailhost <host>)\n");
  240.             return 0;
  241.         }
  242.  
  243.         if (mailbox_name[0] == '\0') {
  244.             printf("mailbox name not defined yet.(pop mailbox <name>)\n");
  245.             return 0;
  246.         }
  247.  
  248.         if (username[0] == '\0') {
  249.             printf("username not defined yet. (pop user <name> <pass>)\n");
  250.             return 0;
  251.         }
  252.  
  253.         if (password[0] == '\0') {
  254.             printf(" Unknown password\n");
  255.             return 0;
  256.         }
  257.  
  258.         if ((ccb = new_ccb()) == NULLCCB) {
  259.             fprintf(stderr,"*** Unable to allocate CCB");
  260.             return 0;
  261.         }
  262.  
  263.         newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL,0);
  264.     }
  265.  
  266.     /* Restart timer */
  267.  
  268.     start_timer(&popcli_t);
  269.     return 0;
  270. }
  271.  
  272. /* this is the master state machine that handles a single SMTP transaction */
  273. /* it is called with a queue of jobs for a particular host. */
  274.  
  275. static void
  276. pop_send(unused,cb1,p) 
  277. int unused;
  278. void *cb1;
  279. void *p;
  280. {
  281.     char *cp;
  282.     struct sockaddr_in fsocket;
  283.     struct pop_ccb    *ccb;
  284.     void pop_csm(struct pop_ccb *);
  285.     void quit_session(struct pop_ccb *);
  286.     int s;
  287.  
  288.     ccb = (struct pop_ccb *)cb1;
  289.     fsocket.sin_family = AF_INET;
  290.     fsocket.sin_addr.s_addr = mailhost;
  291.     fsocket.sin_port = IPPORT_POP;
  292.  
  293.     s = socket(AF_INET,SOCK_STREAM,0);
  294.  
  295.     ccb->state = CALL;
  296.  
  297.     if (connect(s,(char *)&fsocket,SOCKSIZE) == 0) {
  298.         log(s,"Connected to mailhost %s", inet_ntoa(mailhost));
  299.         ccb->network = fdopen(s,"r+t");
  300.     } else {
  301.         cp = sockerr(s);
  302.         log(s,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  303.             (cp != NULLCHAR)? cp: "");
  304.     }
  305.  
  306.     while(1) {
  307.         if (fgets(ccb->buf,BUF_LEN,ccb->network) == NULLCHAR)
  308.             goto quit;
  309.  
  310.         rip(ccb->buf);
  311.         pop_csm(ccb);
  312.         if (ccb->state == EXIT)
  313.             goto quit;
  314.     }
  315. quit:
  316.     log(s,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  317.     fclose(ccb->network);
  318.     if (fd != NULLFILE)
  319.         fclose(fd);
  320.     delete_ccb();
  321. }
  322.  
  323. /* free the message struct and data */
  324.  
  325. static void
  326. delete_ccb()
  327. {
  328.     if (ccb == NULLCCB)
  329.         return;
  330.  
  331.     free((char *)ccb);
  332.     ccb = NULLCCB;
  333. }
  334.  
  335. /* create a new  pop control block */
  336.  
  337. static struct
  338. pop_ccb *new_ccb()
  339. {
  340.     register struct pop_ccb *ccb;
  341.  
  342.     if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULLCCB)
  343.         return(NULLCCB);
  344.     return(ccb);
  345. }
  346.  
  347. /* ---------------------- pop client code starts here --------------------- */
  348.  
  349. void
  350. pop_csm(ccb)
  351. struct pop_ccb    *ccb;
  352. {
  353.     FILE *mf;
  354.  
  355.     int mlock (char *,char *);
  356.     int rmlock (char * ,char *);
  357.     void quit_session(struct pop_ccb *);
  358.     /* int mlock __ARGS((char *dir,char *id));   */
  359.     /* int rmlock __ARGS((char *dir,char *id));   */
  360.  
  361.  
  362.     switch(ccb->state) {
  363.     case CALL:
  364.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  365.              fprintf(ccb->network,login_cmd,username,password);
  366.             ccb->state = NMBR;
  367.         } else
  368.             (void) quit_session(ccb);
  369.         break;
  370.  
  371.     case NMBR:
  372.  
  373.         switch (ccb->buf[0]) {
  374.         case '#':
  375.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  376.                 perror("Unable to open work file");
  377.                 quit_session(ccb);
  378.                 return;
  379.             }
  380.  
  381.             fseek(fd,0,SEEK_SET);
  382.             ccb->folder_len = atoi(&(ccb->buf[1]));
  383.             fprintf(ccb->network,read_cur_cmd);
  384.             ccb->state = SIZE;
  385.             break;
  386.  
  387.         case '+':
  388.  
  389.             /* If there is no mail (the only time we get a "+"
  390.              * response back at this stage of the game),
  391.              * then just close out the connection, because
  392.              * there is nothing more to do!! */
  393.  
  394.         default:
  395.             quit_session(ccb);
  396.             break;
  397.         }
  398.     break;
  399.  
  400.     case SIZE:
  401.         if (ccb->buf[0] == '=') {
  402.             ccb->msg_len = atol(&(ccb->buf[1]));
  403.             if (ccb->msg_len > 0) {
  404.                 fprintf(ccb->network,retr_cmd);
  405.  
  406.                 ccb->state = XFER;
  407.             } else {
  408.                 log(fileno(ccb->network),"POP client retrieved %d messages",
  409.                         ccb->folder_len);
  410.  
  411.                 /* All done, so do local cleanup */
  412.  
  413.                 if (mlock(Mailspool,mailbox_name)) {
  414.                     printf("\n*** Local mailbox locked, new mail in file %s\n",
  415.                          Workfile_name);
  416.                     quit_session(ccb);
  417.                     return;
  418.                 }
  419.  
  420.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  421.                     mailbox_name);
  422.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  423.                     printf("\n*** Unable to open local mailbox, new mail in file %s\n",
  424.                            Workfile_name);
  425.                     quit_session(ccb);
  426.                     return;
  427.                 }
  428.  
  429.                 fseek(fd,0,SEEK_SET);
  430.  
  431.                 while (!feof(fd)) {
  432.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  433.                         fputs(ccb->buf,mf);
  434.                     }
  435.                 }
  436.                 fclose(mf);
  437.                 fclose(fd);
  438.                 fd = NULL;
  439.                 printf("New mail arrived for %s from mailhost <%s>%c\n",
  440.                     mailbox_name, inet_ntoa(mailhost),
  441.                     Popquiet ? ' ' : '\007');
  442.                 rmlock(Mailspool,mailbox_name);
  443.                 unlink(Workfile_name);
  444.                 quit_session(ccb);
  445.             }
  446.         } else
  447.             quit_session(ccb);
  448.         break;
  449.  
  450.         case XFER:
  451.             fprintf(fd,"%s\n",ccb->buf);
  452.  
  453.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);    /* Add CRLF */
  454.  
  455.             if (ccb->msg_len > 0)
  456.                 return;
  457.  
  458.             fprintf(ccb->network,ackd_cmd);
  459.  
  460.             ccb->msg_num++;
  461.             ccb->state = SIZE;
  462.             break;
  463.  
  464.         case EXIT:
  465.             if (fd != NULLFILE)
  466.                 fclose(fd);
  467.             break;
  468.  
  469.         default:
  470.             break;
  471.     }
  472. }
  473.  
  474. void
  475. quit_session(ccb)
  476. struct pop_ccb    *ccb;
  477. {
  478.     fprintf(ccb->network,quit_cmd);
  479.  
  480.     ccb->state  = EXIT;
  481. }
  482.